/*
使用方法
配置好环境：
Android/iOS 权限设置完毕
导入库 flutter_blue

1.初始化
initBle();

2.开始搜索蓝牙设备
startBle();

3.得到搜索到所有蓝牙设备名字数组(含名称过滤/空名、错误名)
getBleScanNameAry

4.从名字数组里面选择对应的蓝牙设备进行连接，传入需要连接的设备名在数组的位置
(其实是假连接，停止扫描，准备好需要连接的蓝牙设备参数)
connectionBle(int chooseBle)

5.正式连接蓝牙，并且开始检索特征描述符，并匹配需要用到的特征描述符等
discoverServicesBle()

6.断开蓝牙连接
disconnect()

*写入数据  例子：writeToDevice([0x00, 0x00, 0x00, 0x00])
writeToDevice(List<int> value)

*收到数据
dataCallbackBle()

更多帮助博客：https://www.jianshu.com/p/bab40d5ecdee
*/

import 'dart:async';
import 'package:flutter_blue_plus/flutter_blue_plus.dart';
import 'package:scoped_model/scoped_model.dart';

//蓝牙UUID
const PERIPHERAL_UUID = '0000fff0-0000-1000-8000-00805f9b34fb'; //'FFF0';
const DEVICE_INFO_SERVICE_UUID =
    '0000180a-0000-1000-8000-00805f9b34fb'; //'180A';
const DEVICE_INFO_CHAR_UUID = '00002a23-0000-1000-8000-00805f9b34fb'; //'2A23';

//写入服务
const SEND_SERVICE_UUID = '0000ffe5-0000-1000-8000-00805f9b34fb'; //'FFE5';
const SEND_SERVICE_UUID_NEW = '6e400001-b5a3-f393-e0a9-e50e24dcca9e';

//写入特征值
const SEND_CHAR_UUID = '0000ffe9-0000-1000-8000-00805f9b34fb'; //'FFE9';
const SEND_CHAR_UUID_NEW = '6e400002-b5a3-f393-e0a9-e50e24dcca9e';

//接收服务
const RECEIVE_SERVICE_UUID = '0000ffe0-0000-1000-8000-00805f9b34fb'; //'FFE0';
const RECEIVE_SERVICE_UUID_NEW = SEND_SERVICE_UUID_NEW;

//接收特征值
const RECEIVE_CHAR_UUID = '0000ffe4-0000-1000-8000-00805f9b34fb'; //'FFE4';
const RECEIVE_CHAR_UUID_NEW = '6e400003-b5a3-f393-e0a9-e50e24dcca9e';

// 所有服务
List<String> servicesList = [
  DEVICE_INFO_SERVICE_UUID,
  SEND_SERVICE_UUID,
  SEND_SERVICE_UUID_NEW,
  RECEIVE_SERVICE_UUID,
  RECEIVE_SERVICE_UUID_NEW
];
// 所有读取特征
List<String> readableCharacteristicsList = [
  DEVICE_INFO_CHAR_UUID,
  RECEIVE_CHAR_UUID,
  RECEIVE_CHAR_UUID_NEW
];
// 所有写入特征
List<String> writableCharacteristicsList = [SEND_CHAR_UUID, SEND_CHAR_UUID_NEW];

// 蓝牙数据模型
class ble_data_model {
  BluetoothDevice? device;
  BluetoothCharacteristic? writeCharacteristic;
  BluetoothCharacteristic? notifyCharacteristic;
  int? sendMaxLength; // 单次最大传输字节数
  bool? manuallyDisconnect; // 手动断开（不重连）
  StreamSubscription? notifySubscription; // 监听接收数据
  BluetoothConnectionState deviceState =
      BluetoothConnectionState.disconnected; // 蓝牙状态
}

// abstract class BleManagerListener {
//   void onDeviceListChange(List list);
// }

// 当前设备连接状态
enum BLESTATE {
  Normal,
  Searching,
  Connecting,
  Connected,
  DisConnecting,
  DisConnected
}

// class BleManager {
class PluginBleManager extends Model {
  // final BleManagerListener _bleManagerListener;
  // BleManager(this._bleManagerListener);
  // void onDeviceListChange(List list) {
  //   _bleManagerListener.onDeviceListChange(model.allDevicesList);
  // }

  // 单例模式
  factory PluginBleManager() => _sharedInstance();
  static PluginBleManager? _instance;

  PluginBleManager._() {
    // 初始化代码
    initBle();
  }

  static PluginBleManager _sharedInstance() {
    if (_instance == null) {
      _instance = new PluginBleManager._();
    }
    return _instance!;
  }

  // ble_data_model model = new ble_data_model();
  Map<String, ScanResult> scanResults = new Map(); // 搜索到的设备列表
  Map<String, ble_data_model> connectedList = new Map(); // 已连接的设备列表
  List<BluetoothDevice> allDevicesList = []; // 过滤后的设备列表

  StreamSubscription? scanSubscription; // 监听搜索结果
  List<String> autoConnectList = []; // 自动连接列表

  BLESTATE? bleState; // 当前设备连接状态

  void initBle() {
    print('🔹 --- 初始化');
    // PermissionHandler()
    // .requestPermissions([PermissionGroup.location]).then((permissions) => {
    // if (permissions[PermissionGroup.location] ==
    //     PermissionStatus.granted)
    //   {print('有定位权限')}
    // else
    //   {print('无定位权限')}
    // });
    // PermissionUtil.requestLocationPermiss(() {});

    // 判断蓝牙是否开启
    FlutterBluePlus.adapterState.listen((state) {
      if (state == BluetoothAdapterState.on) {
        print('🔹 --- 蓝牙状态开启');
      } else if (state == BluetoothAdapterState.off) {
        print('🔹 --- 蓝牙状态关闭');
      }
    });
  }

  void startScan(int timeout) async {
    print('🔹 --- 开始扫描');
    if (bleState == BLESTATE.Searching) {
      print('🔹 --- 正在扫描中，请勿重复操作');
      return;
    }

    allDevicesList = [];
    bleState = BLESTATE.Searching;
    notifyListeners();
    // _scanSubscription = model.flutterBlue.scan(timeout: Duration(seconds: timeout)).listen((results) {
    // }, onDone: stopScan);

    // 开始扫描
    FlutterBluePlus.startScan(timeout: Duration(seconds: timeout));
    // 监听扫描结果
    scanSubscription = FlutterBluePlus.scanResults.listen(
      (results) {
        // 扫描结果 可扫描到的所有蓝牙设备
        for (ScanResult result in results) {
          scanResults[result.device.advName] = result;
          if (result.device.advName.length > 0 &&
              !allDevicesList.contains(result.device)) {
            print(
                '🔹 --- ScanResult - ${result.device.advName} found! ${result.device.remoteId} rssi: ${result.rssi} ');
            allDevicesList.add(result.device);
            // getBleScanNameAry();
            // onDeviceListChange(model.allDevicesList);

            // 自动连接设备
            autoConnectList.forEach((deviceName) {
              if (deviceName == result.device.advName) {
                connectionBle(result.device);
              }
            });

            notifyListeners();
          }
        }
      },
      onDone: stopScan,
    );
  }

// 自动连接
  void setAutoConnectList(List<String> connectList) {
    autoConnectList = connectList;
  }

  void stopScan() {
    // 停止扫描
    FlutterBluePlus.stopScan();
    scanSubscription?.cancel();
    scanSubscription = null;
    bleState = BLESTATE.Normal;
    notifyListeners();
  }

  void setSendMaxLength(String deviceName, int length) {
    ble_data_model? model = connectedList[deviceName];
    if (model?.device != null) {
      model?.sendMaxLength = length;
    }
  }

  // 连接设备
  void connectionBle(BluetoothDevice device) {
    // 停止扫描
    stopScan();

    ble_data_model? model = connectedList[device.advName];
    print('🔹 --- 连接设备 设备状态：${model?.deviceState}');
    if (model?.deviceState == BluetoothConnectionState.connected) {
      print('🔹 --- 当前设备已连接，请勿重复连接');
      return;
    }

    // discoverServicesBle(device);
    // 连接
    device.connect(autoConnect: false, timeout: Duration(seconds: 5));

    device.connectionState.listen((state) {
      ble_data_model? model = connectedList[device.advName];
      model?.deviceState = state;
      notifyListeners();
      if (state == BluetoothConnectionState.connecting) {
        print('🔹 --- 蓝牙状态改变 ${device.advName}：连接中');
        bleState = BLESTATE.Connecting;
      } else if (state == BluetoothConnectionState.connected) {
        print('🔹 --- 蓝牙状态改变 ${device.advName}：已连接');
        discoverServicesBle(device);
      } else if (state == BluetoothConnectionState.disconnecting) {
        print('🔹 --- 蓝牙状态改变 ${device.advName}：正在断开连接');
        bleState = BLESTATE.DisConnecting;
      } else if (state == BluetoothConnectionState.disconnected) {
        print('🔹 --- 蓝牙状态改变 ${device.advName}：已断开连接');
        bleState = BLESTATE.DisConnected;

        // 取消数据监听
        model?.notifySubscription?.cancel();
        model?.notifySubscription = null;

        model?.writeCharacteristic = null;
        model?.notifyCharacteristic = null;

        // // 从连接设备中移除
        // connectedList.remove(device.advName);

        if (model?.manuallyDisconnect == true) {
          print('🔹 --- 手动断开 ${device.advName}，不重连');
        } else {
          if (model?.device != null) {
            stopScan();
            bleState = BLESTATE.Connecting;
            model?.device!
                .connect(autoConnect: false, timeout: Duration(seconds: 5));
            print('🔹 --- 异常断开 正在重连... ${device.advName}');
          } else {
            print('🔹 --- 异常断开 ${device.advName}');
          }
        }
      }
      notifyListeners();
    });
  }

  void discoverServicesBle(BluetoothDevice device) {
    device.discoverServices().then((services) {
      services.forEach((service) {
        var value = service.uuid.toString();
        print('🔹 ---  $value');
        // 根据服务筛选
        if (servicesList.contains(value)) {
          print('🔹 ---  找到对应的服务');
          // 订阅成功，保存连接对象
          ble_data_model? model = connectedList[device.advName];
          if (model == null) {
            model = new ble_data_model();
            connectedList[device.advName] = model;
            print('🔹 --- 创建新蓝牙对象 ---------- ${device.advName}');
          }
          model.deviceState = BluetoothConnectionState.connected;
          model.device = device;
          List<BluetoothCharacteristic> characteristics =
              service.characteristics;
          characteristics.forEach((characteristic) {
            var valuex = characteristic.uuid.toString();
            print('🔹 --- 所有特征值 ${device.advName}：$valuex');
            if (readableCharacteristicsList.contains(valuex)) {
              if (characteristic.descriptors.length > 0) {
                print(
                    '🔹 --- ---------------匹配到读取的特征值 ${device.advName}：$valuex  descriptors 正常');
                if (model?.notifyCharacteristic != null) {
                  return;
                }
                print('🔹 --- 保存读取的特征值 ${device.advName}：$valuex');
                model?.notifyCharacteristic = characteristic;
                dataCallbackBle(device.advName);
                bleState = BLESTATE.Connected;
                notifyListeners();
              } else {
                print(
                    '🔹 --- ---------------匹配到读取的特征值 ${device.advName}：$valuex  descriptors 为空');
              }
            } else if (writableCharacteristicsList.contains(valuex)) {
              print('🔹 --- 匹配到写入的特征值 ${device.advName}：$valuex');
              if (model?.writeCharacteristic != null) {
                return;
              }
              print('🔹 --- 保存写入的特征值 ${device.advName}：$valuex');
              model?.writeCharacteristic = characteristic;
            }
          });
        }
      });
    });
  }

  // void discoverServicesBle(BluetoothDevice device) async {
  //   print('🔹 --- 连接蓝牙设备');
  //   // 设置连接10秒超时
  //   await device.connect(autoConnect: false, timeout: Duration(seconds: 10));
  //   List<BluetoothService> services = await device.discoverServices();
  //   services.forEach((service) {
  //     var value = service.uuid.toString();
  //     // print('🔹 ---  $value');
  //     // 根据服务筛选
  //     if (servicesList.contains(value)) {
  //       // 订阅成功，保存连接对象
  //       ble_data_model model = connectedList[device.advName];
  //       if (model == null) {
  //         model = new ble_data_model();
  //         connectedList[device.advName] = model;
  //       }
  //       model.device = device;
  //       List<BluetoothCharacteristic> characteristics = service.characteristics;
  //       characteristics.forEach((characteristic) {
  //         var valuex = characteristic.uuid.toString();
  //         print('🔹 --- 所有特征值：$valuex');
  //         if (readableCharacteristicsList.contains(valuex)) {
  //           print('🔹 --- 匹配到读取的特征值：$valuex');
  //           dataCallbackBle(device.advName, characteristic);
  //         } else if (writableCharacteristicsList.contains(valuex)) {
  //           print('🔹 --- 匹配到写入的特征值：$valuex');
  //           model.mCharacteristic = characteristic;
  //         }
  //       });
  //     }
  //     // do something with service
  //   });
  // }

  ///发送数据
  ///maxLength 单次最大传输字节
  writeToDevice(String deviceName, List<int> list) {
    ble_data_model? model = connectedList[deviceName];
    if (list.length == 0 || model?.device == null) {
      return;
    }

    print('🔹🔹🔹 ----- 数据准备写入：$list');
    if (model!.sendMaxLength == null ||
        model.sendMaxLength == 0 ||
        list.length <= model.sendMaxLength!) {
      // 如果没配置最大传输字节数，或者长度小于最大字节数，直接发送数据
      model.writeCharacteristic?.write(list);
      print('🔹🔹🔹 ---------- 写入数据 ${model.device?.advName}：$list');
    } else {
      int sendIndex = 0;
      for (int i = 0; i < list.length; i++) {
        if (sendIndex < list.length) {
          int sendSize = list.length - sendIndex;
          if (sendSize > model.sendMaxLength!) {
            sendSize = model.sendMaxLength!;
          }
          List<int> sendList = list.sublist(sendIndex, sendIndex + sendSize);
          model.writeCharacteristic?.write(sendList);
          print('🔹🔹🔹 ---------- 拆包写入 ${model.device?.advName}：$sendList');
          sendIndex += sendSize;
        } else {
          break;
        }
      }
    }
  }

  dataCallbackBle(String deviceName) async {
    ble_data_model? model = connectedList[deviceName];
    await model?.notifyCharacteristic?.setNotifyValue(true);
    model?.notifySubscription =
        model.notifyCharacteristic?.lastValueStream.listen((value) {
      // do something with new value
      print('🔹🔹🔹 ----- 蓝牙返回数据：$value');
      List data = [];
      for (var i = 0; i < value.length; i++) {
        String dataStr = value[i].toRadixString(16);
        if (dataStr.length < 2) {
          dataStr = '0' + dataStr;
        }
        String dataEndStr = '0x' + dataStr;
        data.add(dataEndStr);
      }
      print('🔹🔹🔹 --------------- 蓝牙返回数据：$data');
    });
  }

  void disconnect(String deviceName) {
    ble_data_model? model = connectedList[deviceName];
    if (model?.device != null) {
      model?.manuallyDisconnect = true;
      model?.device?.disconnect();
    }
  }
}
